/*
 * GeoVISTA Center (Penn State, Dept. of Geography)
 * Copyright (c), 2003-2011,  Jin Chen and Alan M. MacEachren, GeoVISTA Center, Penn State University
 * All Rights Researved.
 *
 * This library is developed and distributed for free usage,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * You can redistribute and/or modify it under the terms of the
 * Simplified BSD License
 *
 *
 *
 *
 *
 *
 *  
 *  
 * @author: jin Chen 
 * @date: Aug 19, 2004$
 * @version: 1.0
 */
package edu.psu.geovista.app.pcp.toolkits.selectcontrol;

import edu.psu.geovista.app.pcp.toolkits.selectcontrol.action.ActionManager;
import edu.psu.geovista.app.pcp.toolkits.selectcontrol.ui.VerticalBttnsPane;
import edu.psu.geovista.app.pcp.toolkits.table.ColorConfigureTable;
import edu.psu.geovista.app.pcp.toolkits.table.ConfigureTable;
import edu.psu.geovista.app.pcp.toolkits.table.ConfigureTableModel;
import epoviz.trex.common.swing.components.buttons.ButtonFactory;

import javax.swing.*;
import javax.swing.table.TableModel;
import java.awt.*;
import java.util.Arrays;
import java.util.Hashtable;

public abstract class SelectItemsPane extends JPanel {
    public static final int TABLE_LEFT=1;
    public static final int TABLE_RIGHT=2;

    //public static final O


    ActionManager actMgr;
    //ButtonListner btnListener=new ButtonListner();
    protected Hashtable buttons=new Hashtable();
    protected int[] selectedRows=null;  // 


    public SelectItemsPane() {
        // columnHeaders=new String[]{"Name","Description"};
         actMgr=new ActionManager();
         actMgr.setApp(this);
         initComponents();


        //myTable.getModel().get
    }
    /*******************************************************************************************************
     *                service
     *******************************************************************************************************/
     public void addToControlPane(JComponent c) {
        controlP.setLayout(new FlowLayout(FlowLayout.LEFT) );
        this.controlP.add(c);
        /*if(c instanceof JButton){//by default, add to a toolbar

        }
        else{//

        }*/
     }
    /**************************************************
     * move items back and forth between left/right table
     ***************************************************/
    /**
     *  
     */
    public void setSelectedAttributes(String[] ids){
        if(ids==null||ids.length <=0){
            this.moveAllLeft();
            return;
        }
        //int[] indices=new int[ids.length ];
        for (int i=0;i<ids.length ;i++){
            int row=leftTable.getRowIndexByID(ids[i]);
            if(row>=0){
                leftTable.addSelectedRow(row);
            }
        }

        this.moveRight();


    }

    /**
     * Implementation depend on the column name of the right table.
     * @return   name of selected items
     * @throws Exception
     */
    public abstract String[] getSelectedItemNames() throws Exception; /*{
        Object[] os= rightTable.getSortValueAtColumn("Name");
        String[] itemNames=new String[os.length ];
        for (int i=0;i<itemNames.length ;i++){
            itemNames[i]=(String)os[i];
        }

        return itemNames;
    }*/


    /**
     * move selected item on left table to the right table
     */
    public void moveRight(){
        int[] selectedRows = this.leftTable.getSelectedRows();
        moveRight(selectedRows);


    }

    public void moveRight(int[] rows){
      for (int i=0;i<rows.length ;i++){
            int row=rows[i];
            Object id= leftTable.getRowID(row);
            //String key = this.getIDColumnName();
            //String value=(String) leftTable.getValueAt(row,key);
            Object[] rowData = leftTable.getRowData(row);//,getIDColumnName());
            if(!rightTable.isIDContained(id) ){
                    this.selectRecord(rowData);
                    this.leftTable.colorItem(row,true);
                }

        }
    }
    /**
     * Move all items on the left to right
     */
    public void moveAllRight(){

        int rownum=this.leftTable.getRowCount();
        int[] rows=new int[rownum];
        for (int i=0;i<rows.length ;i++){
            rows[i]=i;
        }
        moveRight(rows);

    }
    /**
     *  
     *  
     * Usually u don't need all the record data that passed as the argument. It is subclass to decide what data it need
     * @param data  the attributes of the selected record in left table
     */
    public abstract void selectRecord(Object[] data);/*{
        Object[] arow={new Integer(-1),name, YAxis.DTYPE_Nml};
                this.myTable.addRow(arow);
    }*/
    /**
     *  
     *  
     * deprecate
     */
    public  void moveLeft(int index){
        // Add your handling code here:
        //int index=this.rightTable.getSelectedRow() ;
        //rightTable.getr
        if(index<0)return ;

        //String key = getIDColumnName();
        //String value= (String) rightTable.getValueAt(index,key);
        Object rowID = rightTable.getRowID(index);
        if(rowID!=null){
            this.rightTable.removeRow(index);
            int row=leftTable.getRowIndexByID(rowID);
            this.leftTable.colorItem(row,false);
          }
    }
    /**
     *  
     *  
     */
    public  void moveLeft(){
        // Add your handling code here:
        //int[] indexs=this.myTable.getSelectedRows();
        int[] indexs=this.getSelectedRows() ;
        if(indexs==null||indexs.length <=0)return ;

        Arrays.sort(indexs);
        for (int i=indexs.length -1;i>=0;i--){
          /*String name= (String) rightTable.getValueAt(indexs[i],getIDColumnName());
          if(name!=null){
            this.rightTable.removeRow(indexs[i]);
            this.myList.colorItem(name,false);
          }*/
          this.moveLeft(indexs[i]);
        }
        //this.setSelectedRows(null);

    }
    public  void moveAllLeft(){
        this.rightTable.removeAllRow() ;
        leftTable.colorAllItem(false);
        //this.myList.colorAllItem(false);
         //this.setSelectedRows(null);

    }
    /**************************************************
     *                move item up/down on right table
     ***************************************************/
    public   void moveUp(){

        int[] rows=this.getSelectedRows() ;
        rightTable.moveRowsUp(rows);
        this.updateSelectedRows(-1);
    }
    public  void moveDown(){

        int[] rows=this.getSelectedRows() ;
        rightTable.moveRowsDown(rows);
        this.updateSelectedRows(1);
    }

    public void moveTop(){
        int[] rows=this.getSelectedRows() ;
        if(rows!=null&&rows.length >0){
            rightTable.moveTop(rows);
        }
    }
    public void moveBottom(){
        int[] rows=this.getSelectedRows() ;
        if(rows!=null&&rows.length >0){
            rightTable.moveBottom(rows);
        }
    }
    public void apply(){
        //this.setSelectedRows(null);
    }
    public int[] getSelectedRows(){
         //if(this.selectedRows ==null){
             this.selectedRows = rightTable.getSelectedRows();
         //}
         return this.selectedRows ;
    }
    /**
     * update the selected row
     * @param delta -1 means make selected row= current selected row -1.
     */
    protected void updateSelectedRows(int delta){
        for (int i=0;i<this.selectedRows.length ;i++){
            int expect=selectedRows[i]+delta;
            if(expect>=0&&expect<this.rightTable.getRowCount() ) {
               selectedRows[i]=expect;
            }
        }
        //select rows
        rightTable.setRowSelectionAllowed(true);
         ListSelectionModel model=rightTable.getSelectionModel();
        for (int i=0;i<selectedRows.length ;i++){
            //myTable.setRowSelectionInterval(selectedRows[i],selectedRows[i]);

            model.addSelectionInterval(selectedRows[i],selectedRows[i]);
        }
    }

    public void setSelectedRows(int[] selectedRows) {
        this.selectedRows = selectedRows;

    }

    public void selectAllAttributes(){
        this.moveAllRight();
    }
     public void deSelectAllAttributes(){
        this.moveAllLeft();
    }

     /*******************************************************************************************************
      * Setup
      *     - column names of left/right table
      *     - column size of left/right table
      *     - set data in left table ( data in right table is (selected) from left table  )
      *
      *******************************************************************************************************/

    /*****************************************************
     *                left table
     *****************************************************/
    /**
     * Defined by subclass. Need provide these functions:
     * - define column names
     * - provide initial data for the table
     * - Define the size of each columns
     *
     * example:
     *          public void initLeftTable() {
                    Object[] arecord=new Object[]{"No data"," "};
                    Object[][] data=new Object[][]{arecord};
                    String[] names=new String[] {Col_Name,Col_Desc};
                    this.setData(data,names);
                    this.setColumnsWidth(new int[]{1,2},SelectDataPane.TABLE_LEFT);
                }
     */
    protected abstract void initLeftTable();

    /**
     * Set data, put it in left table
     * Define column names
     * @param data
     * @param columnNames
     */
    public void setData(Object[][] data, String[] columnNames) {
        //data of right table depend on left table, so if set new data in left table, need clear right table
        if(rightTable.getRowCount() >0)
             rightTable.removeAllRow() ;
        this.leftTable.setData(data,columnNames);
    }
    /**
     *
     * @param data   table model, it is expected to contain data and name of the columns
     */
    public void setData(ConfigureTableModel data){
       if(rightTable.getRowCount() >0)
             rightTable.removeAllRow() ;
        this.leftTable.setModel(data);
        //this.setColumnsWidth(new int[]{1,2},SelectDataPane.TABLE_LEFT);
    }






    /*******************************************
     *               right table
     ******************************************/
    /**
     * Defined by subclass. Need provide these functions:
     * - define column names(Note: right table do not have to have same columns as left table
     * - provide initial table model
     * - define the data type of each column(it is done by define table model)
     * - define the size of each columns
     *
     */
    protected abstract void initRightTable();


    /**************************************************
     *                common for both tables
     ***************************************************/
    /**
     * To set weight of columns
     *  
     * @param weights  weight of each column width. 0 means does not matter
     * @param tableid    if true, it works on the right table, otherwise on the left table
     */
    public void setColumnsWidth(int[] weights, int tableid) {
        if(tableid==TABLE_LEFT){
            this.leftTable.setColumnsWidth(weights);
        }
        else if(tableid==TABLE_RIGHT){
            this.rightTable.setColumnsWidth(weights);
        }

    }
    public void setTableModel(TableModel dataModel,int table) {
        if(table==TABLE_RIGHT)
            this.rightTable.setModel(dataModel);
        else if(table ==TABLE_LEFT){
            this.leftTable.setModel(dataModel);
        }
    }
    /*public void setValueAt(Object value,int row, int col) {
        rightTable.setValueAt(value,row,col);
    }*/
     public Object[] getColumnValues(String  colName, int table){
        if(table==TABLE_RIGHT)
            return rightTable.getColumnValues(colName);
        else if (table ==TABLE_LEFT){
            return leftTable.getColumnValues(colName);
        }
        else{
            return new Object[0];
        }
     }
      public Object[] getColumnValues(int col, int table){
         return rightTable.getColumnValues(col);
     }
    /*******************************************************************************************************
     *                GUI
     *******************************************************************************************************/
     public void setMainSectionName(String name) {
        mainP.setBorder(new javax.swing.border.TitledBorder(name));
     }
    public void setLeftSectionName(String name) {
        LTableP.setBorder(new javax.swing.border.TitledBorder(name));
    }
    public void setRightSectionName(String name) {
        javax.swing.border.TitledBorder border = new javax.swing.border.TitledBorder(name);
        border.setTitleColor(new Color(166,23,104));
        RTableP.setBorder(border);
    }

    /*******************************************************************************************************
     *                button
     *******************************************************************************************************/
    protected void initButtons() {
        /*String[] names=new String[]{"Right","Left","Right all","Left all","Up","Down","Apply"};
        this.addButtons(names);*/

    }

   /* public void addButtons(String[] names) {
        int numBtn=names.length;
        btnP.removeAll() ;

        this.btnP.setLayout(new GridLayout(numBtn, 1)) ;
        for (int i=0;i<numBtn ;i++){
             JButton btn=new JButton(names[i]);
             btn.setMargin(new Insets(2,2,2,2));
             btn.setName(names[i]);
             btn.addActionListener(this.btnListener );
             btnP.add(btn);
             this.buttons.put(names[i],btn);
        }
    }*/
    public JButton getButton(String name) {
        return (JButton) this.buttons.get(name);
    }
    public Action getAction(String name){
        return this.actMgr.getAction(name);
    }
    /**
     * you can add any component in the middle panel which contain the button.
     * All components in the panel is listed from top to bottom in one column. The sequence is same as the order they are added
     * It is your responsibility to listen the component's behavoir
     *
     * @param comp
     */
    public void addComponentToMiddlePanel(JComponent comp) {
        btnP.add(comp);
        Component[] comps=btnP.getComponents();
        if(comps!=null&&comps.length >0){
            int numOfComp=comps.length ;
            this.btnP.setLayout(new GridLayout(numOfComp+1, 1)) ;
        }
        else{
            this.btnP.setLayout(new GridLayout(1, 1)) ;
        }
    }
    /*public void setButtonPane(SingleButtonsPane p) {
        
        btnP.removeAll();
        btnP.setLayout(new BorderLayout());
        btnP.add(p);
        mainP.invalidate();
        p.addActionListnerForAll(this.btnListener );
        this.revalidate() ;

    }*/
    public void setNumOfComponentInMiddlePanel(int numOfComp) {

    }
    /*******************************************************************************************************
     *                Event
     *******************************************************************************************************/
     /**
      * Implement how to react on clicking a buttons
      * @param btnName
      * @throws Exception
      * e.g.:
      *      protected void actOnButtonClick(String btnName) throws Exception {
                    if(btnName.equals(Btn_Select) ){
                        doSelect();

                    }
                    else if(btnName.equals(Btn_Deselect) ){
                        doDeSelect() ;
                    }
                    else if(btnName.equals(Btn_SelectAll) ){
                        this.doSelectAll();
                    }
                    else if(btnName.equals(Btn_DeselectAll) ){
                        this.doDeSelectAll();
                    }
                    else if(btnName.equals("Apply")){
                        this.doApply() ;

                    }
                }
      *
      */
     protected  abstract void actOnButtonClick(String btnName) throws Exception;





    /*******************************************************************************************************
     *                support
     *******************************************************************************************************/
    protected  VerticalBttnsPane createSelectBttnsPane() {
        Action right = this.getAction(ActionManager.ACTION_RIGHT);
        JButton btn1 = ButtonFactory.createButton(right);


        //JButton btn2 = btnPane.getBtn2();
        Action rightall = this.getAction(ActionManager.ACTION_RIGHTALL);
        JButton btn2 = ButtonFactory.createButton(rightall);
        //btn2.setText("");


        Action left = this.getAction(ActionManager.ACTION_LEFT);
        JButton btn3 = ButtonFactory.createButton(left);
        //btn3.setText("");

        Action leftall = this.getAction(ActionManager.ACTION_LEFTALL);
        JButton btn4 = ButtonFactory.createButton(leftall);


        VerticalBttnsPane vbp=new VerticalBttnsPane();
        JToolBar tb=vbp.getToolbar() ;


        tb.add(btn1);
        tb.add(btn2);
        tb.add(btn3);
        tb.add(btn4);
        return vbp;
    }
    protected  VerticalBttnsPane createUpDownBttnsPane() {
        Action top = this.getAction(ActionManager.ACTION_TOP);
        JButton btn1 = ButtonFactory.createButton(top);


        //JButton btn2 = btnPane.getBtn2();
        Action up = this.getAction(ActionManager.ACTION_UP);
        JButton btn2 = ButtonFactory.createButton(up);
        //btn2.setText("");


        Action down = this.getAction(ActionManager.ACTION_DOWN);
        JButton btn3 = ButtonFactory.createButton(down);
        //btn3.setText("");

        Action bottom = this.getAction(ActionManager.ACTION_BOTTOM);
        JButton btn4 = ButtonFactory.createButton(bottom);


        VerticalBttnsPane vbp=new VerticalBttnsPane();
        JToolBar tb=vbp.getToolbar() ;


        tb.add(btn1);
        tb.add(btn2);
        tb.add(btn3);
        tb.add(btn4);
        return vbp;
    }
    /**************************************************
     *                GUI setup
     ***************************************************/

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    private void initComponents() {
        GridBagConstraints gridBagConstraints;


       //create components

        createComponents();
        //placement
        layoutComponents();


        initButtons()   ;
    }

    protected  void layoutComponents() {
        GridBagConstraints gridBagConstraints;
        setLayout(new GridBagLayout());
        setPreferredSize(new Dimension(400, 375));

        mainP.setLayout(new GridBagLayout());
        btnP.setLayout(new GridLayout(9, 1));

        //for button panel

        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 0;
        /*gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;*/
        mainP.add(btnP, gridBagConstraints);

        //layout table
        layoutTables();
        //layoutRightTable();





        /*gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        add(mainP, gridBagConstraints);*/
        this.setLayout(new BorderLayout());
        this.add(mainP);
        //controlP.add(new JButton("test"));
        this.add(controlP,BorderLayout.NORTH );
    }

    protected void layoutTables() {
        layoutTable(TABLE_LEFT,new Dimension(273, 349),new Point(0,0),new Point(1,1));
        layoutTable(TABLE_RIGHT,new Dimension(273, 349),new Point(3,0),new Point(1,1));
    }

    /**
     *
     * @param tableId
     * @param size       Dimension(w,h)
     * @param location   gridx, gridy
     * @param weight
     */
    protected  void layoutTable(int tableId,Dimension size,Point location,Point weight) {
        JPanel tableP=null;
        JScrollPane sp=null;
        ConfigureTable table=null;
        if(tableId==TABLE_LEFT){
           tableP=LTableP;
           sp=LTableScrollPane;
           table=leftTable;
        }
        else if(tableId==TABLE_RIGHT){
           tableP=RTableP;
           sp=RTableScrollPane;
           table=rightTable;
        }
        else{
            throw new IllegalArgumentException("Must specify left or right table");
        }
        GridBagConstraints gridBagConstraints;
        tableP.setLayout(new BorderLayout());

        tableP.setBorder(new javax.swing.border.TitledBorder(""));
        tableP.setPreferredSize(size); //473,349
        sp.setViewportView(table);
        tableP.add(sp, BorderLayout.CENTER);
        //tableP.setBorder(new javax.swing.border.TitledBorder("Visible"));
        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx =location.x ;//0;
        gridBagConstraints.gridy =location.y;// 0;
        gridBagConstraints.gridwidth = 2;
        gridBagConstraints.fill = GridBagConstraints.BOTH;
        gridBagConstraints.weightx = weight.x;//1.0; //todo 1.0
        gridBagConstraints.weighty = weight.y;//1.0;
        mainP.add(tableP, gridBagConstraints);
    }

   /* protected  void layoutRightTable() {
        GridBagConstraints gridBagConstraints;
        //right table
        RTableP.setLayout(new BorderLayout());

        RTableP.setBorder(new javax.swing.border.TitledBorder(""));
        RTableP.setPreferredSize(new Dimension(273, 349)); //473,349
        RTableScrollPane.setViewportView(rightTable);
        RTableP.add(RTableScrollPane, BorderLayout.CENTER);
        //tableP.setBorder(new javax.swing.border.TitledBorder("Visible"));
        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.fill = GridBagConstraints.BOTH;
        gridBagConstraints.gridx = 3;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        mainP.add(RTableP, gridBagConstraints);
    }*/

    private void createComponents() {
        mainP = new JPanel();
        btnP = new JPanel();
        RTableP = new JPanel();
        RTableP.setLayout(new BorderLayout());
        RTableScrollPane = new JScrollPane();
        rightTable = new ConfigureTable();

        LTableP = new JPanel();
        LTableP.setLayout(new BorderLayout());
        LTableScrollPane = new JScrollPane();
        leftTable = new ColorConfigureTable();
    }

    /*protected void createComponents(){

    }*/

    protected ConfigureTable rightTable;//data destination, store selected data
    protected ColorConfigureTable leftTable;//data source, supposed to stored original data
    protected JScrollPane RTableScrollPane;
    protected JPanel RTableP;
    protected JScrollPane LTableScrollPane;
    protected JPanel LTableP;
    //protected ColorItemList myList;
    //protected JScrollPane ListScrollPane;
    //protected JPanel listP;

    protected JPanel btnP;  //contain buttons for select/deselect
    protected JPanel mainP; // 
    protected JPanel rootP;
    protected JPanel controlP=new JPanel(); //contain other buttons like sorting, picking...


   /* private class ButtonListner implements ActionListener{
            public void actionPerformed(java.awt.event.ActionEvent evt) {

                JButton btn=(JButton) evt.getSource();

                //System.out.println("click on :"+btn.getName() );
                try {
                    actOnButtonClick(btn.getName());
                } catch (Exception e) {
                    e.printStackTrace();
                    //JOptionPane.showMessageDialog(this,e.getMessage());
                }
            }
    }*/


}
